﻿using System;
using System.Collections.Generic;
using System.Text;

using Jim.Obsidian.Utilities;
using Jim.Obsidian.Edm;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;

namespace Jim.Obsidian.Web.Api.Client
{
    public class ApiRequest
    {

        private Dictionary<string, object> postParams = new Dictionary<string, object>();
        private string _action;
        private ApiResult _apiResult;

        public string Action
        {
            get { return this._action; }
            set { this._action = value; }
        }

        public ApiRequest() { }

        public ApiRequest(string action)
        {
            this.Action = action;
        }

        public Dictionary<string, object> Params
        {
            get { return postParams; }
        }

        public ApiResult Result
        {
            get { return this._apiResult; }
            set { this._apiResult = value; }
        }

        public ApiSubResult GetSubResult(string name)
        {
            return this._apiResult.GetSubResult(name);
        }

        public ApiRequest Set(string name, object val)
        {
            postParams[name] = val;
            return this;
        }

        public ApiRequest SetModel(Model model)
        {
            IModelField[] fields = model.Fields;
            foreach (IModelField field in fields)
            {
                if (field.Type == FieldType.String && field.OValue == null)
                {
                    postParams[field.JPropName] = "";
                    continue;
                }
                else if (field.Type == FieldType.DateTime)
                {
                    DateTime dt = Convert.ToDateTime(field.OValue);
                    if (dt == DateTime.MinValue)
                        postParams[field.JPropName] = "";
                    else
                        postParams[field.JPropName] = dt.ToString("yyyy-MM-dd HH:mm:ss");
                    continue;
                }
                else
                {
                    postParams[field.JPropName] = Convert.ToString(field.OValue);
                    continue;
                }
            }
            return this;
        }

        public ApiRequest Set(Model model)
        {
            IModelField[] fields = model.Fields;
            foreach (IModelField field in fields)
            {
                if (field.Type == FieldType.DateTime)
                    postParams[field.JPropName] = field.ToString();
                else if (field.Type == FieldType.Bool)
                    postParams[field.JPropName] = Convert.ToBoolean(field.OValue) ? 1 : 0;
                else if (field.Type == FieldType.String)
                    postParams[field.JPropName] = field.OValue == null ? "" : Convert.ToString(field.OValue);
                else
                {
                    object val = field.OValue;
                    if (val != null)
                        postParams[field.JPropName] = val;
                }
            }
            return this;
        }

        public object Get(string name)
        {
            if (postParams.ContainsKey(name))
                return postParams[name];
            else
                return null;
        }

        public void Remove(string name)
        {
            postParams.Remove(name);
        }

        public JObject GetJOject()
        {
            JObject jo = new JObject();
            JValue jvAction = new JValue(this._action);
            jo.Add("act", jvAction);
            JObject joData = new JObject();
            jo.Add("data", joData);
            foreach (string name in postParams.Keys)
            {
                JValue jvVal = new JValue(postParams[name]);
                joData.Add(name, jvVal);
            }
            return jo;
        }


        private static readonly string APP_NAME = "quan";


        public static void Post(params ApiRequest[] reqs)
        {
            ApiInfo apiInfo = AppConfig.GetApiInfo(APP_NAME);
            Post(apiInfo.Name,
                apiInfo.AppKey,
                apiInfo.Url,
                reqs);
        }

        public static void Post(string name, string appkey, string url,
            params ApiRequest[] reqs)
        {
            JObject jo = new JObject();
            List<string> paramsList = new List<string>();
            string timestamp = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
            paramsList.Add("appName=" + name);
            paramsList.Add("appKey=" + appkey);
            paramsList.Add("timestamp=" + timestamp);
            JArray jarr = new JArray();
            jo.Add("reqs", jarr);
            foreach (ApiRequest req in reqs)
            {
                paramsList.Add(RequestParamsSortByString(req));
                jarr.Add(req.GetJOject());
            }
            paramsList.Sort();
            string strParams = ArrayUtility.Join(paramsList, "&");
            string sign = StringUtility.AspMD5(strParams);
            jo.Add("appName", name);
            jo.Add("appKey", appkey);
            jo.Add("timestamp", timestamp);
            jo.Add("sign", sign);
            string jsonString = JsonConvert.SerializeObject(jo);
            string responseString = HttpRequestor.Post(url, jsonString, 600000);
            ParseApiResults(responseString, reqs);
        }

        private static void ParseApiResults(string responseString, params ApiRequest[] reqs)
        {
            JObject jo = (JObject)JsonConvert.DeserializeObject(responseString);
            DateTime serverDateTime = DateTime.Parse(
                Convert.ToString(((JValue)jo["sdt"]).Value));
            JArray jaRsus = (JArray)jo["rsus"];
            for (int i = 0; i < reqs.Length; i++)
            {
                JObject joRs = (JObject)jaRsus[i];
                ApiResult result = new ApiResult(joRs, serverDateTime);
                reqs[i].Result = result;
            }
        }

        private static string RequestParamsSortByString(ApiRequest req)
        {
            string act = req.Action;
            List<string> paramsList = new List<string>();
            Dictionary<string, object> reqParams = req.Params;
            paramsList.Add("act=" + req.Action);
            if (reqParams.Count > 0)
            {
                foreach (string name in reqParams.Keys)
                {
                    object o = reqParams[name];
                    paramsList.Add(name + "=" + o.ToString());
                }
            }
            paramsList.Sort();
            return ArrayUtility.Join(paramsList, "&");
        }

    }
}
